package cn.schoolwow.quickdao.module.database.ddl.query.flow.entity;

import cn.schoolwow.quickdao.domain.database.parent.DatabaseType;
import cn.schoolwow.quickdao.domain.entity.Entity;
import cn.schoolwow.quickdao.module.database.parent.domain.ResultSetConsumer;
import cn.schoolwow.quickdao.module.database.parent.flow.executor.ExecuteQueryConnectionFlow;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

public class GetEntityFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        DatabaseType databaseType = flowContext.checkInstanceData(DatabaseType.class);

        switch (databaseType){
            case H2:{
                getByH2(flowContext);
            }break;
            case SQLite:{
                getBySQLite(flowContext);
            }break;
            case Mysql:
            case MariaDB:{
                getByMysql(flowContext);
            }break;
            case Postgresql:{
                getByPostgres(flowContext);
            }break;
            case SQLServer:{
                getBySQLServer(flowContext);
            }break;
            case Oracle:{
                getByOracle(flowContext);
            }break;
        }

        String tableName = (String) flowContext.checkData("tableName");
        if(null==flowContext.getData("entity")){
            flowContext.broken("表不存在!表名:"+tableName);
        }
    }

    @Override
    public String name() {
        return "获取数据库指定表信息";
    }

    private void getByH2(FlowContext flowContext) {
        String tableName = (String) flowContext.checkData("tableName");
        flowContext.executeFlowList(new GetEntityListFlow());
        List<Entity> entityList = (List<Entity>) flowContext.checkData("entityList");
        for(Entity entity:entityList){
            if(entity.tableName.equalsIgnoreCase(tableName)){
                flowContext.putData("entity", entity);
                break;
            }
        }
    }

    private void getBySQLite(FlowContext flowContext) {
        String tableName = (String) flowContext.checkData("tableName");
        flowContext.startFlow(new ExecuteQueryConnectionFlow())
                .putTemporaryData("name", "获取指定表信息")
                .putTemporaryData("sql", "select name from sqlite_master where type = 'table' and name = ?;")
                .putTemporaryData("parameters", Arrays.asList(tableName))
                .putReturnData("resultSetConsumer",new ResultSetConsumer() {
                    @Override
                    public void consumeResultSet(ResultSet resultSet) throws Exception {
                        if(resultSet.next()){
                            Entity entity = new Entity();
                            entity.tableName = resultSet.getString("name");
                            flowContext.putData("entity", entity);
                        }
                    }
                })
                .execute();
    }

    private void getByMysql(FlowContext flowContext) {
        String tableName = (String) flowContext.checkData("tableName");
        flowContext.startFlow(new ExecuteQueryConnectionFlow())
                .putTemporaryData("name", "获取指定表信息")
                .putTemporaryData("sql", "show table status;")
                .putReturnData("resultSetConsumer",new ResultSetConsumer() {
                    @Override
                    public void consumeResultSet(ResultSet resultSet) throws Exception {
                        while(resultSet.next()){
                            if(tableName.equalsIgnoreCase(resultSet.getString("name"))){
                                Entity entity = new Entity();
                                entity.tableName = resultSet.getString("name");
                                entity.comment = resultSet.getString("comment").replace("\"", "\\\"");
                                flowContext.putData("entity", entity);
                                break;
                            }
                        }
                    }
                })
                .execute();
    }

    private void getByPostgres(FlowContext flowContext) {
        String tableName = (String) flowContext.checkData("tableName");
        flowContext.startFlow(new ExecuteQueryConnectionFlow())
                .putTemporaryData("name", "获取指定表信息")
                .putTemporaryData("sql", "select relname as name,cast(obj_description(relfilenode,'pg_class') as varchar) as comment from pg_class c where relkind = 'r' and relname = ? order by relname;")
                .putTemporaryData("parameters", Arrays.asList(tableName))
                .putReturnData("resultSetConsumer",new ResultSetConsumer() {
                    @Override
                    public void consumeResultSet(ResultSet resultSet) throws Exception {
                        if(resultSet.next()){
                            Entity entity = new Entity();
                            entity.tableName = resultSet.getString("name");
                            entity.comment = resultSet.getString("comment");
                            flowContext.putData("entity", entity);
                        }
                    }
                })
                .execute();
    }

    private void getBySQLServer(FlowContext flowContext){
        String tableName = (String) flowContext.checkData("tableName");
        flowContext.startFlow(new ExecuteQueryConnectionFlow())
                .putTemporaryData("name", "获取指定表信息")
                .putTemporaryData("sql", "select name from sysobjects where xtype='u' and name = ? order by name;")
                .putTemporaryData("parameters", Arrays.asList(tableName))
                .putReturnData("resultSetConsumer",new ResultSetConsumer() {
                    @Override
                    public void consumeResultSet(ResultSet resultSet) throws Exception {
                        if(resultSet.next()){
                            Entity entity = new Entity();
                            entity.tableName = resultSet.getString("name");
                            flowContext.putData("entity", entity);
                        }
                    }
                })
                .execute();
        if(flowContext.containKey("entity")){
            Entity entity = (Entity) flowContext.checkData("entity");
            flowContext.startFlow(new ExecuteQueryConnectionFlow())
                    .putTemporaryData("name", "获取指定表注释信息")
                    .putTemporaryData("sql", "select so.name table_name, isnull(convert(varchar(255),value),'') comment from sys.extended_properties ex_p left join sys.sysobjects so on ex_p.major_id = so.id where ex_p.minor_id=0 and so.name = ?;")
                    .putTemporaryData("parameters", Arrays.asList(tableName))
                    .putReturnData("resultSetConsumer",new ResultSetConsumer() {
                        @Override
                        public void consumeResultSet(ResultSet resultSet) throws Exception {
                            if (resultSet.next()) {
                                entity.comment = resultSet.getString("comment");
                            }
                        }
                    })
                    .execute();
        }
    }

    private void getByOracle(FlowContext flowContext) throws SQLException {
        String tableName = (String) flowContext.checkData("tableName");
        flowContext.startFlow(new ExecuteQueryConnectionFlow())
                .putTemporaryData("name", "获取指定表信息")
                .putTemporaryData("sql", "select user_tables.table_name,user_tab_comments.comments from user_tables left join user_tab_comments on user_tables.table_name = user_tab_comments.table_name where user_tables.table_name = ?")
                .putTemporaryData("parameters", Arrays.asList(tableName))
                .putReturnData("resultSetConsumer",new ResultSetConsumer() {
                    @Override
                    public void consumeResultSet(ResultSet resultSet) throws Exception {
                        if(resultSet.next()){
                            Entity entity = new Entity();
                            entity.tableName = resultSet.getString("table_name");
                            entity.comment = resultSet.getString("comments");
                            flowContext.putData("entity", entity);
                        }
                    }
                })
                .execute();
    }
}
